module Main where
import IO
import Char
import System.Time
import System.Locale
import System.Environment

main = do {

		putStrLn "------------------------------------------------";
		putStrLn "----------------------SPOP----------------------";
		putStrLn "Projekt: Obsluga rezerwacji miejsc w restauracji";
		putStrLn "--Autorzy: Marcin Strzalek, Krzysztof Sienicki--";
		putStrLn "------------------------------------------------";
		menu;
}


----------------------------------------------------------------------------------------
--glowna petla programu, odpowiedzialna za wyswietlanie menu i interakcji z uzytkownikiem
----------------------------------------------------------------------------------------
menu = do {
			putStrLn "-----------------MENU GLOWNE--------------------"; 
			putStrLn "(1) Edycja informacji o stolikach";
			putStrLn "(2) Edycja informacji o rezerwacji";
			putStrLn "(3) Wyszukanie wolnych stolikow";
			putStrLn "(4) Wyszukanie rezerwacji";
			putStrLn "(5) Wyswietl wszystkie dane o stolikach";
			putStrLn "(6) Wyswietl wszystkie dane o rezerwacjach";
			putStrLn "(7) Wyjscie";
			
			putStrLn "Wybierz polecenie:";
			cmd <- getLine;
 
			case cmd of
				"1" -> do {
							putStrLn "(w) Wprowadzenie informacji o stoliku";--ok
							putStrLn "(m) Modyfikacja informacji o stoliku";
							putStrLn "(u) Usuniecie informacji o stoliku";
							opt <- getLine;
							case opt of
								"w" -> do {
									putStrLn "Podaj numer stolika: ";
									nr_stolika <- getLine;
									putStrLn "Podaj liczbe miejsc przy stoliku: ";
									liczba_miejsc <- getLine;
									dodajStolik nr_stolika liczba_miejsc;
									menu;
								};
								"m" -> do {
									putStrLn "Podaj numer stolika: ";
									nr_stolika_przed <- getLine;
									putStrLn "Podaj liczbe miejsc przy stoliku: ";
									liczba_miejsc_przed <- getLine;
									putStrLn "Podaj nowy numer stolika: ";
									nr_stolika_po <- getLine;
									putStrLn "Podaj nowa liczbe miejsc przy stoliku: ";
									liczba_miejsc_po <- getLine;
									modyfikujStolik nr_stolika_przed liczba_miejsc_przed nr_stolika_po liczba_miejsc_po;
									menu;
								};
								"u" -> do {
									putStrLn "Podaj numer stolika: ";
									nr_stolika <- getLine;
									putStrLn "Podaj liczbe miejsc przy stoliku: ";
									liczba_miejsc <- getLine;
									usunStolik nr_stolika liczba_miejsc;
									menu;
								};
								otherwise -> do {
									putStrLn "Podano bledna wartosc";
									menu;
								};
						}
				"2" -> do {
							putStrLn "(w) Wprowadzenie informacji o rezerwacji";--ok
							putStrLn "(m) Modyfikacja informacji o rezerwacji";
							putStrLn "(u) Usuniecie informacji o rezerwacji";
							opt <- getLine;
							case opt of
								"w" -> do {
									putStrLn "Podaj numer stolika: ";
									nr_stolika <- getLine;
									putStrLn "Podaj dzien w formacie (rrrrmmdd): ";
									data_rezerwacji <- getLine;
									putStrLn "Podaj godzine w formacie (ggmm): ";
									godzina_rezerwacji <- getLine;
									putStrLn "Podaj nazwisko: ";
									nazwisko <- getLine;
									putStrLn "Podaj informacje dodatkowe: ";
									info <- getLine;
									dodajRezerwacje nr_stolika data_rezerwacji godzina_rezerwacji nazwisko info;
									menu;
								};
								"m" -> do {
									putStrLn "Podaj numer stolika: ";
									nr_stolika_przed <- getLine;
									putStrLn "Podaj dzien w formacie (rrrrmmdd): ";
									data_rezerwacji_przed <- getLine;
									putStrLn "Podaj godzine w formacie (ggmm): ";
									godzina_rezerwacji_przed <- getLine;
									putStrLn "Podaj nazwisko: ";
									nazwisko_przed <- getLine;
									putStrLn "Podaj informacje dodatkowe: ";
									info_przed <- getLine;
									putStrLn "Podaj nowy numer stolika: ";
									nr_stolika_po <- getLine;
									putStrLn "Podaj nowy dzien w formacie (rrrrmmdd): ";
									data_rezerwacji_po <- getLine;
									putStrLn "Podaj nowa godzine w formacie (ggmm): ";
									godzina_rezerwacji_po <- getLine;
									putStrLn "Podaj nowe nazwisko: ";
									nazwisko_po <- getLine;
									putStrLn "Podaj nowe informacje dodatkowe: ";
									info_po <- getLine;
									modyfikujRezerwacje nr_stolika_przed data_rezerwacji_przed godzina_rezerwacji_przed nazwisko_przed info_przed nr_stolika_po data_rezerwacji_po godzina_rezerwacji_po nazwisko_po info_po;
									menu;
								};
								"u" -> do {
									putStrLn "Podaj numer stolika: ";
									nr_stolika <- getLine;
									putStrLn "Podaj dzien w formacie (rrrrmmdd): ";
									data_rezerwacji <- getLine;
									putStrLn "Podaj godzine w formacie (ggmm): ";
									godzina_rezerwacji <- getLine;
									putStrLn "Podaj nazwisko: ";
									nazwisko <- getLine;
									putStrLn "Podaj informacje dodatkowe: ";
									info <- getLine;
									usunRezerwacje nr_stolika data_rezerwacji godzina_rezerwacji nazwisko info;
									menu;
								};
								otherwise -> do {
									putStrLn "Podano bledna wartosc";
									menu;
								};
						}
				"3" -> do {
							putStrLn "Podaj dzien do wyszukania wolnych stolikow w formacie (rrrrmmdd): ";
							pattern <- getLine;
							if (length pattern == 8) then
								wolnyStolik "rezerwacje.txt" "stoliki.txt" pattern
							else 
								putStrLn "Podano bledna date";
							menu
						}
				"4" -> do {
							putStrLn "Podaj kategorie wg ktorej chcesz szukac rezerwacji: ";
							putStrLn "(1)nr stolika (2)dzien 3)godzina (4)nazwisko (5)informacje dodatkowe: ";
							category <- getLine;
							putStrLn "Podaj ciag znakow jaki chcesz wyszukac: ";
							pattern <- getLine;
							case category of 
								"1" -> do{ wyszukajInfo "rezerwacje.txt" pattern 1; menu;}
								"2" -> do{ wyszukajInfo "rezerwacje.txt" pattern 2; menu;}
								"3" -> do{ wyszukajInfo "rezerwacje.txt" pattern 3; menu;}
								"4" -> do{ wyszukajInfo "rezerwacje.txt" pattern 4; menu;}
								"5" -> do{ wyszukajInfo "rezerwacje.txt" pattern 5; menu;}
								otherwise -> do {
									putStrLn "Podano bledna wartosc";
									menu;
								};
						}
				"5" -> do {
							wczytajPlik "stoliki.txt";
							menu
						}
				"6" -> do {
							wczytajPlik "rezerwacje.txt";
							menu
						}
				"7" -> return();
				otherwise -> do {
								putStrLn "Podano bledna wartosc";
								menu;
							};
		 }

-- funkcja dodaje stolik
dodajStolik nr lm = catch( do {
							hand <- openFile "stoliki.txt" ReadWriteMode;
							y <- istniejaceStoliki hand [];
							hClose hand;
							if (jestLiczba nr && jestLiczba lm && not (elem (string2int nr) y) ) then do 
							{
								zapiszWiersz "stoliki.txt" (nr++" "++lm);
								putStrLn ("Nowy stolik "++nr++" "++lm++" zostal wprowadzony");
							}
							else putStrLn "Podano bledne dane";
						} ) errorHandler
						where
							errorHandler e = ioError e
										 
-- funkcja modyfikuje stolik
modyfikujStolik nr_przed lm_przed nr_po lm_po = do {
							old_row <- return(nr_przed++" "++lm_przed);
							new_row <-return(nr_po++" "++lm_po);
							if (jestLiczba nr_przed && jestLiczba lm_przed && jestLiczba nr_po && jestLiczba lm_po) then do 
							{
								modyfikujDane "stoliki.txt" old_row new_row;
							}
							else putStrLn "Podano bledne dane";
						}

-- funkcja usuwa stolik
usunStolik nr lm = catch( do {
							hand <- openFile "rezerwacje.txt" ReadWriteMode;
							y <- zrobListe hand "0" [];
							old_row <- return(nr++" "++lm);
							if (jestLiczba nr && jestLiczba lm) then do 
							{
								if (elem (string2int nr) y) then putStrLn "Stolik nie moze zostac usuniety, bo istnieje na niego rezerwacja"
								else do {
									modyfikujDane "stoliki.txt" old_row "";
								}
							}
							else putStrLn "Podano bledne dane";
						} ) errorHandler
						where
							errorHandler e = ioError e

-- funkcja dodaje rezerwacje
dodajRezerwacje nr dat godz naz info = catch( do { 
							hand <- openFile "stoliki.txt" ReadWriteMode;
							y <- istniejaceStoliki hand [];
							hClose hand;
							dzis <- zwrocDate;
							if (jestLiczba nr && jestLiczba dat && (length dat == 8) && sprawdzDate dat dzis && jestLiczba godz && (length godz == 4)
								&& jestTekstem naz && sprawdzGodzine godz && elem (string2int nr) y ) then do 
							{
								zapiszWiersz "rezerwacje.txt" (nr++" "++dat++" "++godz++" "++naz++" "++info);
								putStrLn ("Nowa rezerwacja "++nr++" "++dat++" "++godz++" "++naz++" "++info++" zostala przyjeta");
							}
							else putStrLn "Podano bledne dane";
						} ) errorHandler
						where
							errorHandler e = ioError e

-- funkcja modyfikuje rezerwacje
modyfikujRezerwacje nr_przed dat_przed godz_przed naz_przed info_przed nr_po dat_po godz_po naz_po info_po = catch( do {
							hand <- openFile "stoliki.txt" ReadWriteMode;
							y <- istniejaceStoliki hand [];
							hClose hand;
							dzis <- zwrocDate;
							old_row <- return(nr_przed++" "++dat_przed++" "++godz_przed++" "++naz_przed++" "++info_przed);
							new_row <- return(nr_po++" "++dat_po++" "++godz_po++" "++naz_po++" "++info_po);
							if (jestLiczba nr_przed && jestLiczba dat_przed && (length dat_przed == 8) && jestLiczba godz_przed && (length godz_przed == 4)
								&& jestTekstem naz_przed && sprawdzGodzine godz_przed && jestLiczba nr_po && jestLiczba dat_po && (length dat_po == 8)
								&& sprawdzDate dat_po dzis && jestLiczba godz_po && (length godz_po == 4) && jestTekstem naz_po && sprawdzGodzine godz_po
								&& elem (string2int nr_po) y ) then do
							{
								modyfikujDane "rezerwacje.txt" old_row new_row;
							}
							else putStrLn "Podano bledne dane";
						} ) errorHandler
						where													--zabezpieczenie przed nieistniejacym plikiem
							errorHandler e = ioError e

-- funkcja usuwa rezerwacje
usunRezerwacje nr dat godz naz info = do {
							old_row <- return(nr++" "++dat++" "++godz++" "++naz++" "++info);
							if (jestLiczba nr && jestLiczba dat && (length dat == 8) && jestLiczba godz && (length godz == 4) && sprawdzGodzine godz
							    && jestTekstem naz) then do
							{
								modyfikujDane "rezerwacje.txt" old_row "";
							}
							else putStrLn "Podano bledne dane";
						}

--funkcja odpowiadajaca za wczytanie plikow	
wczytajPlik fname = catch( do {
							handle <- openFile fname ReadWriteMode;
							wczytajWiersz handle;
							hClose handle;
						} ) errorHandler
						where
							errorHandler e = ioError e

-- funkcja wyswietlajaca zawartosc wierszy hdl - uchwyt pliku							
wczytajWiersz hdl = do {
							t <- hIsEOF hdl;						
							if t then return()
							else do {
								contents <- hGetLine hdl;
								x<-return(contents);
								if x == [] then return()
								else putStrLn contents;
								wczytajWiersz hdl 
							}
						}

-- funkcja sluzaca do zapisu do pliku okreslonego przez fname zawartosci contentns														
zapiszWiersz fname contents = catch ( do {
							handle <- openFile fname AppendMode;
							hPutStrLn handle contents;
							hClose handle
						} ) errorHandler
						where
							errorHandler e = ioError e

-- funkcja sluzaca do modyfikacji danych
modyfikujDane fname row newrow = catch ( do { 
							handle <- openFile fname ReadWriteMode;
							contents <- hGetContents handle;
							zawartosc <- return $! (contents);			-- scisle wartosciowanie
							hClose handle;
							handle <- openFile fname WriteMode;
							modyfikujWiersz handle zawartosc row newrow False;
							hClose handle;
						} ) errorHandler
						where
							errorHandler e = ioError e
						
-- funkcja sluzaca do modyfikacji danych wyszukuje wiersz lub jego czesc (row) i zamienia go na newrow
-- bool przechowuje informacje, czy chociaz jeden wiersz zostal zmodyfikowany
modyfikujWiersz hdl contents row newrow bool = do {
							if (szukajwzorca contents ("\n")) then do {
								if (szukajwzorca (getWiersz contents) row) then do {
									contents <- return(removeWiersz contents);
									hPutStrLn hdl newrow;
									modyfikujWiersz hdl (bez_new_line (removeWiersz contents)) row newrow True;
								}
								else do {
									--putStrLn (getWiersz contents);
									hPutStrLn hdl (getWiersz contents);
									modyfikujWiersz hdl (bez_new_line (removeWiersz contents)) row newrow bool;
								}
							}
							else 
								if (bool==False) then
									putStrLn ("Nie znaleziono wpisu: "++row)
								else if (newrow=="") then
									putStrLn ("Wpis "++row++" zostal usuniety")
								else do {
									putStrLn ("Poprzednia wartosc: "++row);
									putStrLn ("Obecna wartosc: "++newrow);
								}
						}

-- funkcja pobiera wiersz z zawartosci xs takeWhile do znaku nowej linii
getWiersz [] = [];		
getWiersz (xs) = do {
				takeWhile (/='\n') xs;
			}

-- fukncja usuwa wiersz - dropWhile do znaku nowej lini (trzeba pozniej uzyc bez_new_line) 		
removeWiersz [] = [];
removeWiersz (xs) = do {
				dropWhile (/='\n') xs;
			}

-- funkcja konwertuje string do inta
string2int [] = 0
string2int [x] | isDigit x == True = digitToInt x
			   | otherwise = 0
string2int (x:xs) | isDigit x == True = 10^length xs * digitToInt x + string2int xs
				  | otherwise = 0
						
-- funkcja szuka wzorca okreslonego przez x:xs w tekscie y:ys
szukajwzorca [] [] = True
szukajwzorca _ [] = True
szukajwzorca [] _ = False							
szukajwzorca (x:xs) (y:ys) = if x==y then szukajwzorca xs ys 
							 else szukajwzorca xs (y:ys)

-- funkcja sluzaca do wyszukiwania informacji w pliku okreslonej przez pattern - tekst  a jaki mamy wsyzkuakc
-- i numer kolumny (kategorii) w jakiej mamy szukac odpowiada za to funkcja szukaj
wyszukajInfo fname pattern i = catch ( do {
							handle <- openFile fname ReadWriteMode;
							szukaj handle pattern i False;
							hClose handle;
						} ) errorHandler
						where
							errorHandler e = ioError e

-- funkcja szukaj wyszukuje wzoraca okreslonego przez str w kolumnie i 		
-- bool przechowuje informacje, czy znaleziono jakis obiekt spelniajacy wymagania				 
szukaj hdl str i bool = do {
							t <- hIsEOF hdl;							
							if t then do {
								if (bool==False) then
									putStrLn "Nie znaleziono rezerwacji spelniajacej wymagania"
								else
									putStrLn "";
							}
							else do {
								contents <- hGetLine hdl;
								x<-return(contents);
								if x == [] then				--zabezpieczenie przed pustymi wierszami w pliku
									szukaj hdl str i bool
								else if (szukajwzorca (pobierz_pole x i) str) then do { 	--sprawdzenie czy dana linijka pasuje do wzorca
									putStrLn x;
									szukaj hdl str i True;
								}
								else
									szukaj hdl str i bool;
							}
						}
									
-- funkcje pomocnicze usuwajace spacje i znaki nowej lini
bez_spacji (x:xs) = xs;
bez_new_line (x:xs) = xs;

-- funkcja pobiera i-te pole z wiersza (krotki) xs
-- separatorami sa spacje
pobierz_pole (xs) i = do {
							if (i==1) then
								takeWhile (/=' ') xs
							else
								pobierz_pole (bez_spacji (dropWhile (/=' ') xs)) (i-1);
						}

-- funkcja sprawdza, czy stolik (z pliku fname2) nie jest danego dnia (date) zarezerwowany (z pliku fname1)
wolnyStolik fname1 fname2 date = catch( do {
							handle1 <- openFile fname1 ReadWriteMode;
							handle2 <- openFile fname2 ReadWriteMode;
							y <- zrobListe handle1 date [];
							wolny handle2 y False;
							hClose handle1;
							hClose handle2;
						} ) errorHandler
						where
							errorHandler e = ioError e

-- funkcja wypisuje dane dotyczace kazdego wolnego stolika
-- bool przechowuje informacje, czy znaleziono jakis obiekt
wolny hdl y bool = do {
							t <- hIsEOF hdl;
							if (t) then do {
								if (bool==False) then
									putStrLn "Nie znaleziono wolnego stolika"
								else
									putStrLn "";
							}
							else do {
								cont <- hGetLine hdl;
								x <- return(cont);
								if x == [] then				--zabezpieczenie przed pustymi wierszami w pliku
									wolny hdl y bool
								else if (not (elem ( string2int (pobierz_pole x 1) ) y ) ) then do {
									putStrLn x;
									wolny hdl y True;
								}
								else
									wolny hdl y bool;
							}
						}

-- funkcja tworzy liste numerow stolikow, ktore sa juz zarezerwowane na dany dzien (jesli date==0 to wszystkie stoliki, na ktore jest rezerwacja)
zrobListe hdl date (xs) = do {
							t <- hIsEOF hdl;
							if (t) then return xs
							else do {
								cont <- hGetLine hdl;
								x <- return(cont);
								if x==[] then zrobListe hdl date xs
								else if (date/="0" && (pobierz_pole x 2)==date) then zrobListe hdl date ( (string2int (pobierz_pole x 1) ): xs)
								else if (date=="0" && not (elem (string2int (pobierz_pole x 1) ) xs) ) then zrobListe hdl date ( (string2int (pobierz_pole x 1) ): xs)
								else zrobListe hdl date xs;
							}
						}

-- funkcja sprawdza, czy zadany string jest liczba
jestLiczba [] = False
jestLiczba [x] = if isDigit x then True
				 else False
jestLiczba (x:xs) = if isDigit x then jestLiczba xs
					else False
					
-- funkcja sprawdza, czy zadany string jest tekstem
jestTekstem [] = False
jestTekstem [x] = if isAlpha x then True
				  else False
jestTekstem (x:xs) = if isAlpha x then jestTekstem xs
					 else False

-- funkcja sluzaca do porownywania dat jezeli x:xs > d:ds to true
sprawdzDate [] [] = True
sprawdzDate (x:xs) [] = False
sprawdzDate (x:xs) (d:ds) = if x == ' ' then False
                            else if x> d then True
                            else if x==d then sprawdzDate xs ds
                            else if x<d then False
                            else False

-- funkcja sluaca spradzeniu poprawnosci formatu wprowadzonej godziny
sprawdzGodzine [] = False
sprawdzGodzine (a:b:c:d:e) = if ( (a=='0' || a=='1') && (isDigit b) && c>='0' && c<='5' && (isDigit d) && e==[]) then True
							 else if (a=='2' && b>='0' && b<='3' && c>='0' && c<='5' && (isDigit d) && e==[]) then True
							 else False
							
-- zwraca aktualna date				 
zwrocDate = do {
				time <- (getClockTime >>= toCalendarTime);
				return $ formatCalendarTime defaultTimeLocale "%Y%m%d" time;	
			}
														
-- funkcja zwraca liste numerow stolikow istniejacych w pliku stoliki.txt
istniejaceStoliki hdl (xs) = do {
							t <- hIsEOF hdl;
							if (t) then return xs
							else do {
								cont <- hGetLine hdl;
								x <- return(cont);
								if x==[] then istniejaceStoliki hdl xs
								else istniejaceStoliki hdl ( (string2int (pobierz_pole x 1) ): xs);
							}
						}